package com.carefree.system.modules.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carefree.common.emus.StatusCodeEnum;
import com.carefree.common.exception.BusinessException;
import com.carefree.system.common.utils.RouterUtils;
import com.carefree.system.common.utils.SecurityUtils;
import com.carefree.system.modules.admin.dao.MenuDao;
import com.carefree.system.modules.admin.entity.MenuEntity;
import com.carefree.system.modules.admin.entity.RoleEntity;
import com.carefree.system.modules.admin.entity.RoleMenuEntity;
import com.carefree.system.modules.admin.service.MenuService;
import com.carefree.system.modules.admin.service.RoleMenuService;
import com.carefree.system.modules.admin.service.RoleService;
import com.carefree.system.modules.admin.vo.AssginMenuVo;
import com.carefree.system.modules.admin.vo.RouterVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 菜单
 *
 * @author tengbin
 */
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuDao, MenuEntity> implements MenuService {

    @Resource
    private RoleMenuService roleMenuService;

    @Resource
    private RoleService roleService;

    @Resource
    private MenuDao menuDao;

    @Resource
    private SecurityUtils securityUtils;


    /**
     * 获取菜单列表
     *
     * @return
     */
    @Override
    public List<MenuEntity> getMenusWithTree() {
        // 1.先获取所有菜单信息
        List<MenuEntity> allMenuList = list();
        // 2.为空就直接返回null,不为空就递归
        return allMenuList.isEmpty() ? null : buildMenuTree(allMenuList);
    }

    /**
     * 递归构建菜单树
     *
     * @param allMenuList
     * @return
     */
    private List<MenuEntity> buildMenuTree(List<MenuEntity> allMenuList) {
        return allMenuList.stream().filter(menuEntity -> menuEntity.getParentId() == 0) //将父级菜单过滤掉
                .map(menuEntity -> {
                    menuEntity.setChildren(getChildrenMenus(menuEntity, allMenuList)); // 递归查找子菜单
                    return menuEntity;
                }).sorted((menu1, menu2) -> (menu1.getSortValue() == null ? 0 : menu1.getSortValue()) - (menu2.getSortValue() == null ? 0 : menu2.getSortValue()))  // 排序
                .collect(Collectors.toList());
    }

    private List<MenuEntity> getChildrenMenus(MenuEntity root, List<MenuEntity> allMenuList) {
        return allMenuList.stream().filter(menuEntity1 -> menuEntity1.getParentId().equals(root.getId()))
                .map(menuEntity -> {
                    menuEntity.setParentName(root.getName());
                    menuEntity.setChildren(getChildrenMenus(menuEntity, allMenuList)); // 如果子菜单下还有子菜单,则继续递归
                    return menuEntity;
                }).sorted((childrenMenu1, childrenMenu2) -> (childrenMenu1.getSortValue() == null ? 0 : childrenMenu1.getStatus()) - (childrenMenu2.getSortValue() == null ? 0 : childrenMenu2.getStatus()))
                .collect(Collectors.toList());
    }

    /**
     * 启用或禁用
     *
     * @param id     菜单id
     * @param status 状态
     * @return
     */
    @Override
    public boolean activeOrInActiveById(Long id, Integer status) {
        if (Objects.isNull(id) || Objects.isNull(status)) {
            return false;
        }
        MenuEntity menuEntity = getById(id);
        if (menuEntity != null) {
            menuEntity.setStatus(status);
            return updateById(menuEntity);
        }
        return false;
    }

    /**
     * 根据菜单id删除菜单
     *
     * @param menuId
     * @return
     */
    @Override
    public boolean removeMenuById(Long menuId) {
        if (Objects.isNull(menuId)) {
            return false;
        }
        // 查询需删除的菜单是否还有子菜单(id=parentId)
        QueryWrapper<MenuEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", menuId);
        long count = count(queryWrapper);
        // 没有就删除,有就返回false
        return count == 0 && removeById(menuId);
    }

    /**
     * 查询 type (类型) 不是 2(按钮)的菜单信息
     *
     * @return
     */
    @Override
    public List<MenuEntity> queryNotButtonTypeMenuList() {
        List<MenuEntity> notButtonList = list(new QueryWrapper<MenuEntity>().notIn("type", 2));

        // 添加父级菜单(需添加的菜单不是二级菜单的情况)
        MenuEntity menu = new MenuEntity();
        menu.setId(0L);
        menu.setName("一级菜单");
        menu.setParentId(0L);
        menu.setStatus(1);
        notButtonList.add(menu);

        return notButtonList;
    }

    /**
     * 根据角色id获取菜单信息
     *
     * @param roleId 角色id
     * @return
     */
    @Override
    public List<MenuEntity> queryMenusByRoleIdToAssign(Long roleId) {
        if (roleId == null || roleId == 0) {
            throw new BusinessException(StatusCodeEnum.DATA_ERROR);
        }
        List<Long> assignedMenuIds = Collections.emptyList();
        // 1.如果上述的角色id不为空,则查询role和menu关系表
        List<RoleMenuEntity> roleMenuList = roleMenuService.list(new QueryWrapper<RoleMenuEntity>().eq("role_id", roleId));
        if (! CollectionUtils.isEmpty(roleMenuList)) {
            // 遍历查询出的集合,将已分配的菜单id收集成一个list
            assignedMenuIds = roleMenuList.stream().map(RoleMenuEntity::getMenuId).collect(Collectors.toList());
        }

        // 2.查询出状态值为1的菜单信息
        List<MenuEntity> menuList = list(new QueryWrapper<MenuEntity>().eq("status", 1));
        if (! CollectionUtils.isEmpty(menuList)) {
            for (MenuEntity menu : menuList) {
                menu.setSelect(assignedMenuIds.contains(menu.getId()));
            }
            return buildMenuTree(menuList);
        }

        return Collections.emptyList();
    }

    /**
     * 根据角色id分配菜单
     *
     * @param assginMenuVo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean assignMenuForRole(AssginMenuVo assginMenuVo) {
        if (assginMenuVo == null) {
            throw new BusinessException(StatusCodeEnum.DATA_ERROR);
        }
        Long roleId = assginMenuVo.getRoleId();
        List<Long> menuIdList = assginMenuVo.getMenuIdList();

        // 查询前端传过来的角色id是否存在
        RoleEntity selectRole = roleService.getOne(new QueryWrapper<RoleEntity>().eq("id", roleId));

        if (Objects.nonNull(selectRole)) {
            // 查询这个角色是否已分配过菜单
            long roleMenuCount = roleMenuService.count(new QueryWrapper<RoleMenuEntity>().eq("role_id", roleId));

            if (roleMenuCount > 0 && CollectionUtils.isEmpty(menuIdList)) {
                // 如果能查询到该角色,且前端传过来的菜单集合为空,那么就表示取消原有菜单分配
                return roleMenuService.remove(new QueryWrapper<RoleMenuEntity>().eq("role_id", roleId));
            } else {

                roleMenuService.remove(new QueryWrapper<RoleMenuEntity>().eq("role_id", roleId));

                List<RoleMenuEntity> needSaveRoleMenuList = menuIdList.stream().map(menuId -> {
                    RoleMenuEntity roleMenuEntity = new RoleMenuEntity();
                    roleMenuEntity.setRoleId(roleId);
                    roleMenuEntity.setMenuId(menuId);
                    return roleMenuEntity;
                }).collect(Collectors.toList());

                return roleMenuService.saveBatch(needSaveRoleMenuList);
            }
        }
        return false;
    }

    /**
     * 根据用户id查询该用户所拥有的所有菜单信息
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public List<RouterVo> getMenusByUserId(Long userId) {
        List<MenuEntity> userMenus = menuDao.selectMenusByUserId(userId);

        if (! CollectionUtils.isEmpty(userMenus)) {
            List<MenuEntity> menuTreeList = buildMenuTree(userMenus);
            return RouterUtils.buildRouters(menuTreeList);
        }
        return Collections.emptyList();
    }

    /**
     * 根据用户id查询拥有的按钮权限列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<String> getMenuButtonsByUserId(Long userId) {
        List<MenuEntity> userMenus = menuDao.selectMenusByUserId(userId);
        if (! CollectionUtils.isEmpty(userMenus)) {
            return userMenus.stream().filter(menuEntity -> menuEntity.getType() == 2).map(MenuEntity::getPerms).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    /**
     * 保存
     *
     * @param menu
     * @return
     */
    @Override
    public boolean saveMenu(MenuEntity menu) {
        menu.setCreator(securityUtils.getPrincipalForUserId());
        return save(menu);
    }

    /**
     * 修改
     *
     * @param menu
     * @return
     */
    @Override
    public boolean updateMenuById(MenuEntity menu) {
        menu.setModifier(securityUtils.getPrincipalForUserId());
        return updateById(menu);
    }
}
